# support
$from tetragen import *
$tetragen = Tetragen()
$nameList = ['tetragen']

# program
#Prog : StList : a0 = filter(bool, a1) ;
Prog : StList : a0 = a1 ;

# list of Statements
#StL : St : a0 = a1 ;
StList : St SEMICOLON : a0 = a1 ;
StList : StList St SEMICOLON: a0 = a1 + a2 ;


# code block
#StBlock : LFPAREN StList RFPAREN : a0 = tetragen.closeBlock(a2) ;

# statements
St : VarDecl : a0 = a1 ;
St : VarAssign : a0 = a1 ;
St : StBlock : a0 = a1 ;

St : PrintSt : a0 = a1 ;
St : ReadSt  : a0 = a1 ;

St : LabelSt : a0 = a1 ;
St : GotoSt : a0 = a1 ;

St : IfSt : a0 = a1 ;
St : WhileSt : a0 = a1 ;
St : ForSt : a0 = a1 ;

St : FuncDef  : a0 = a1 ;
#St : FuncCall : a0 = a1 ;

# functions
ArgDeclList  : VarDecl : a0 = a1 ;
ArgDeclList  : ArgDeclList COLON VarDecl : a0 = a1 + a3 ;
FuncDef  : ID ID LPAREN ArgDeclList RPAREN StBlock : a0 = tetragen.funcDef(a1, a2, a4, a6) ;
FuncDef  : ID ID LPAREN RPAREN StBlock : a0 = tetragen.funcDef(a1, a2, [], a5) ;

#ArgList : ID COLON : a0 = [ tetragen.getVar(a1)[1], tetragen.getVar(a1)[3] ] ;
#ArgList : ArgList COLON ID : a0 = a1 +  tetragen.getVar(a3)[1] ] ;
#FuncCall : ID LPAREN ArgList RPAREN : a0 = a2 ;
#FuncCall : ID LPAREN RPAREN : a0 = a1 ;

# variable actions
VarDecl   : ID ID : a0 = tetragen.addVar(a1, a2) ;
VarAssign : ID EQUALS Expr : a0 = tetragen.assignValue(tetragen.getVar(a1)[1], a3) ;

# expressions
ExprParen : DOUBLE   : a0 = tetragen.getConst(float(a1), 'float') ;
ExprParen : DIGIT    : a0 = tetragen.getConst(int(a1), 'int') ;
ExprParen : ID       : a0 = tetragen.getVar(a1) ;
ExprParen : LPAREN Expr RPAREN : a0 = a2 ;

ExprMul : ExprParen : a0 = a1 ;
ExprMul : ExprMul MULT ExprParen : a0 = tetragen.mul(a1, a3) ;
ExprMul : ExprMul DIV  ExprParen : a0 = tetragen.div(a1, a3) ;

ExprSum : ExprMul : a0 = a1 ;
ExprSum : ExprSum PLUS  ExprMul : a0 = tetragen.sum(a1, a3) ;
ExprSum : ExprSum MINUS ExprMul : a0 = tetragen.sub(a1, a3) ;

# comparaions
ExprComp : ExprSum : a0 = a1
ExprComp : NOT ExprComp : a0 = tetragen.boolNot(a2) ;
ExprComp : ExprComp LESS   ExprSum : a0 = tetragen.less(a1, a3) ;
ExprComp : ExprComp GREAT  ExprSum : a0 = tetragen.more(a1, a3) ;
ExprComp : ExprComp LEQU   ExprSum : a0 = tetragen.lessEq(a1, a3) ;
ExprComp : ExprComp GEQU   ExprSum : a0 = tetragen.moreEq(a1, a3) ;
ExprComp : ExprComp EQUALS ExprSum : a0 = tetragen.eq(a1, a3) ;
ExprComp : ExprComp NEQU   ExprSum : a0 = tetragen.neq(a1, a3) ;

Expr : ExprComp : a0 = a1

# IO
PrintSt : print Expr : a0 = tetragen.printValue(a2) ;
ReadSt  : read  ID   : a0 = tetragen.readValue(tetragen.getVar(a2)) ;


# conditionals
IfSt    : if LPAREN Expr RPAREN St : a0 = tetragen.ifSt(a3, a5)    ;
WhileSt : while LPAREN Expr RPAREN LFPAREN StList RFPAREN : a0 = tetragen.whileSt(a3, a6) ;
#WhileStInner: StList : a0 = a1

ForAssign : VarAssign : a0 = a1 ;
ForCond : Expr : a0 = a1 ;
ForInner : ForAssign COLON ForCond COLON ForAssign COLON : a0 = a1, a3, a5 ;
ForSt : for LPAREN ForInner RPAREN St : a0 = tetragen.forSt(*(a3 + (a5,))) ;

LabelSt : label ID : a0 = tetragen.defLabel(a2) ;
GotoSt  : goto  ID : a0 = tetragen.gotoLabel(a2) ;
